#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
@Author   : long.hai
@Contact  : 1982964634@qq.com
"""
import os
import sys

from _record import drive_js

curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]
sys.path.append(rootPath)
import json
import queue
import asyncio
import websockets
from websockets.exceptions import ConnectionClosedError, ConnectionClosedOK
from asyncio import sleep
from utils.log_tool import info
from playwright.async_api import async_playwright
from utils.common import gen_code_to_str, get_gen_script_line, now
from _base.base import BasePage
from _controller.debugger import single_debug, batch_debug

# 获取桌面截图
UTILS_DIR = os.path.dirname(__file__)
# 截取项目路径
ROOT_DIR = os.path.dirname(UTILS_DIR)
# 创建队列
message_queue = queue.Queue()
# 全局变量
send_record_conn = False
control_conn = False
record_status = False
page = None
# 存储所有连接的客户端，防止客户端意外断开服务器未断开
connected = {"client_ip": None, "websocket": None}


async def send_record_steps(websocket):
    global send_record_conn
    global record_status
    global page
    client_ip = websocket.remote_address[0]
    # 客户端连接以达上限
    if send_record_conn:
        if client_ip == connected["client_ip"]:
            # 关闭已连接websocket并重新连接
            await connected["websocket"].close()
    # 从新保存连接对象
    connected["client_ip"], connected["websocket"] = client_ip, websocket
    send_record_conn = True
    try:
        # 将消息发送到远程桌面
        element_id = None
        async with async_playwright() as playwright:
            base_page = BasePage(playwright, ws=websocket)
            await base_page.conn_debug_chrome()
            await base_page.set_default_timeout(**{"params": 10000})
            page = base_page.page
            await page.reload()
            await page.wait_for_load_state('load')
            await page.evaluate(drive_js.on_load)
            await page.evaluate(drive_js.js_clean_elements)
            await page.evaluate(drive_js.locator_js)
            await page.evaluate(drive_js.set_load_status)
            while send_record_conn:
                try:
                    await sleep(0.2)
                    re_load_status = await page.evaluate(drive_js.get_test_onbeforeunload)
                    str_element = await page.evaluate(drive_js.get_test_elements)
                    if str_element:
                        element = json.loads(str_element)
                        if element_id != element["id"]:
                            element_id = element["id"]
                            step_template = {
                                "by_locators": [
                                    {
                                        "by": element["by"],
                                        "params": element["locator"]
                                    }
                                ],
                                "action_method": {
                                    "action": element["action"],
                                    "params": element['value'] if 'value' in element else ''
                                },
                                "current_line": element["id"],
                                "page": element["page"],
                                "code": 2000
                            }
                            await websocket.send(json.dumps(step_template, ensure_ascii=False))
                    if re_load_status and re_load_status == '0':
                        print("页面已刷新")
                        element_id = None
                        await page.evaluate(drive_js.on_load)
                        await page.evaluate(drive_js.locator_js)
                        await page.evaluate(drive_js.js_clean_elements)
                        await page.evaluate(drive_js.set_load_status)

                except ConnectionClosedError:
                    send_record_conn = False
                except ConnectionClosedOK:
                    send_record_conn = False
                except:
                    print("page失效，重新连接")
                    base_page = BasePage(playwright, ws=websocket)
                    await base_page.conn_debug_chrome()
                    await base_page.set_default_timeout(**{"params": 10000})
                    page = base_page.page
                    element_id = None
                    await page.evaluate(drive_js.on_load)
                    await page.evaluate(drive_js.locator_js)
                    await page.evaluate(drive_js.js_clean_elements)
                    await page.evaluate(drive_js.set_load_status)
    finally:
        # 从连接集合中移除断开的连接
        if connected["websocket"]:
            await connected["websocket"].close()


async def remote_control(websocket):
    global control_conn
    global send_record_conn
    global record_status
    control_conn = True
    try:
        # 将消息发送到远程桌面
        while control_conn:
            try:
                async for message in websocket:
                    msg_json = json.loads(message)
                    action = msg_json["action"]

                    # 连接成功后的操作
                    if action == "onopen":
                        await websocket.send('{"code": 1000}')

                    # 调试
                    elif action == "handler_page":
                        await handler_page(msg_json, websocket)
                    elif action == "testing":
                        pass

                    # 收到start消息，刷新当前行数，开始录制
                    elif action == "start":
                        record_status = True
                        current_line = get_gen_script_line()
                        res_msg = json.dumps({"code": 2001, "current_line": current_line})
                        await websocket.send(res_msg)
                    # 收到pause消息，暂停录制
                    elif action == "pause":
                        record_status = False
                        # activate_window(get_window_title("Chromium"))
                    elif action == "switch":
                        app_name = msg_json["name"]
                        pass
                        # if app_name == 'chrome':
                        #     activate_window(get_window_title("Google Chrome"))
                        # elif app_name == 'chromium':
                        #     activate_window(get_window_title("Chromium"))

                    # 收到close消息，关闭所有连接
                    elif action == "close":
                        control_conn = False
                        send_record_conn = False
                        record_status = False
                        break
            except ConnectionClosedError:
                control_conn = False
            except ConnectionClosedOK:
                control_conn = False
    finally:
        control_conn = False
        record_status = False
        # 从连接集合中移除断开的连接
        print(f"{now()}: RC连接方断开连接")
        # info("RC连接方断开连接")


async def handler_page(msg_json, websocket):
    try:
        async with async_playwright() as playwright:
            base_page = BasePage(playwright, ws=websocket)
            await base_page.conn_debug_chrome()
            hand_type = msg_json["type"]
            await base_page.set_default_timeout(**{"params": 10000})
            if hand_type == "single":
                variable = msg_json["variable"]
                data = msg_json["data"]
                await single_debug(base_page, variable, data)
            elif hand_type == "batch":
                variable = msg_json["variable"]
                data = msg_json["data"]
                await batch_debug(base_page, variable, data)
            elif hand_type == "call_method":
                # 调用单个方法
                result = await getattr(base_page, msg_json['method'])(**msg_json['data'])
                msg_json['result'] = result
                await websocket.send(json.dumps(msg_json))
    except Exception as e:
        print(f"handler_page error: {str(e)}")
        raise e


def start_send_record_steps_server(ip, port):
    asyncio.set_event_loop(asyncio.new_event_loop())
    asyncio.get_event_loop().run_until_complete(
        websockets.serve(send_record_steps, ip, port, close_timeout=10))
    asyncio.get_event_loop().run_forever()


# 启动控制WebSocket服务
def start_ctrl_server(ip, port):
    asyncio.set_event_loop(asyncio.new_event_loop())
    asyncio.get_event_loop().run_until_complete(
        websockets.serve(remote_control, ip, port))
    asyncio.get_event_loop().run_forever()


async def my_tester():
    async with async_playwright() as playwright:
        my_playwright = BasePage(playwright)
        # firefox chromium
        await my_playwright.conn_debug_chrome()
        await asyncio.sleep(5)

# if __name__ == '__main__':
#     asyncio.run(my_tester())
# 返回消息状态码关系对照
# 1000  开始录制应用启动完成
# 2000  发送py代码转为json的步骤数据
# 2001  刷新行号，即获取录制代码最新行数
# 2002  发送测试数据：变量

# 200 执行中，返回进度和日志
# 202 发送用例变量
# 201 执行完成
# 500 执行错误
